package com.frank.oj.service.entity.common.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.frank.model.entity.common.File;
import com.frank.oj.mapper.FileMapper;
import com.frank.oj.model.vo.ACMContestRankVO;
import com.frank.oj.model.vo.OIContestRankVO;
import com.frank.oj.service.entity.common.FileEntityService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

/**
 * @author frank
 * @Date 2024/1/25
 */
@Service
public class FileEntityServiceImpl extends ServiceImpl<FileMapper, File> implements FileEntityService {
    @Resource
    private FileMapper fileMapper;

    @Override
    public List<File> queryCarouselFileList() {
        LambdaQueryWrapper<File> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(File::getType, "carousel");

        return fileMapper.selectList(queryWrapper);
    }

    @Override
    public void updateFileToDeleteByUidAndType(String uid, String type) {
        LambdaUpdateWrapper<File> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(File::getUid, uid)
                .eq(File::getType, type)
                .set(File::getDelete, 1);

        fileMapper.update(null, updateWrapper);
    }

    @Override
    public List<List<String>> getContestRankExcelHead(List<String> contestProblemDisplayIDList, boolean isACM) {
        List<List<String>> headList = new LinkedList<>();

        List<String> head0 = new LinkedList<>();
        head0.add("Rank");
        List<String> head1 = new LinkedList<>();
        head1.add("Username");
        List<String> head2 = new LinkedList<>();
        head2.add("ShowName");
        List<String> head3 = new LinkedList<>();
        head3.add("Real Name");
        List<String> head4 = new LinkedList<>();
        head4.add("School");

        headList.add(head0);
        headList.add(head1);
        headList.add(head2);
        headList.add(head3);
        headList.add(head4);

        List<String> head5 = new LinkedList<>();
        if (isACM) {
            head5.add("AC");
            List<String> head6 = new LinkedList<>();
            head6.add("Total Submission");
            List<String> head7 = new LinkedList<>();
            head7.add("Total Penalty Time");
            headList.add(head5);
            headList.add(head6);
            headList.add(head7);
        } else {
            head5.add("Total Score");
            headList.add(head5);
        }

        for (String displayID : contestProblemDisplayIDList) {
            List<String> tmp = new LinkedList<>();
            tmp.add(displayID);
            headList.add(tmp);
        }
        return headList;
    }

    /**
     * 将ACM比赛排名信息转换为Excel行列表。
     *
     * @param acmContestRankVOList        包含ACM比赛排名信息的列表，每个元素都是ACMContestRankVO类型。
     * @param contestProblemDisplayIDList 比赛问题的显示ID列表，用于确定要展示哪些问题的信息。
     * @param rankShowName                排名显示名称，用于确定在排名列表中显示哪个字段（如用户名、真实姓名或昵称）。
     * @return 返回一个列表的列表，每个子列表代表Excel的一行数据。
     */
    @Override
    public List<List<Object>> changeACMContestRankToExcelRowList(List<ACMContestRankVO> acmContestRankVOList, List<String> contestProblemDisplayIDList, String rankShowName) {
        List<List<Object>> allRowDataList = new LinkedList<>();
        // 遍历比赛排名信息，将每条信息转换为Excel行数据
        for (ACMContestRankVO acmContestRankVO : acmContestRankVOList) {
            List<Object> rowData = new LinkedList<>();
            // 添加排名信息，未排名则用"*"表示
            rowData.add(acmContestRankVO.getRank() == -1 ? "*" : acmContestRankVO.getRank().toString());
            // 添加用户名
            rowData.add(acmContestRankVO.getUsername());

            // 根据rankShowName添加相应的姓名信息（用户名、真实姓名或昵称）
            if ("username".equals(rankShowName)) {
                rowData.add(acmContestRankVO.getUsername());
            } else if ("realname".equals(rankShowName)) {
                rowData.add(acmContestRankVO.getRealname());
            } else if ("nickname".equals(rankShowName)) {
                rowData.add(acmContestRankVO.getNickname());
            } else {
                rowData.add("");
            }
            // 添加真实姓名、学校、AC题数、总题数和总用时
            rowData.add(acmContestRankVO.getRealname());
            rowData.add(acmContestRankVO.getSchool());
            rowData.add(acmContestRankVO.getAc());
            rowData.add(acmContestRankVO.getTotal());
            rowData.add(acmContestRankVO.getTotalTime());

            // 处理提交信息，为每个问题添加相应的状态标识
            HashMap<String, HashMap<String, Object>> submissionInfo = acmContestRankVO.getSubmissionInfo();
            for (String displayId : contestProblemDisplayIDList) {
                HashMap<String, Object> problemInfo = submissionInfo.getOrDefault(displayId, null);
                if (problemInfo != null) {
                    // 计算并添加提交状态信息
                    boolean isAC = (boolean) problemInfo.getOrDefault("isAC", false);
                    boolean isAfterContest = (boolean) problemInfo.getOrDefault("isAfterContest", false);
                    String info = "";
                    int errorNum = (int) problemInfo.getOrDefault("errorNum", 0);
                    int tryNum = (int) problemInfo.getOrDefault("tryNum", 0);
                    if (isAC) {
                        // AC状态的特殊处理
                        if (errorNum == 0) {
                            info = "+(1)";
                        } else {
                            info = "+(" + (errorNum + 1) + ")";
                        }
                        if (isAfterContest) {
                            info += "*";
                        }
                    } else {
                        // 非AC状态的标记
                        if (tryNum != 0 && errorNum != 0) {
                            info = "-(" + errorNum + "+" + tryNum + ")";
                        } else if (errorNum != 0) {
                            info = "-(" + errorNum + ")";
                        } else if (tryNum != 0) {
                            info = "?(" + tryNum + ")";
                        }
                    }
                    rowData.add(info);
                } else {
                    // 若无提交信息，则添加空字符串
                    rowData.add("");
                }
            }
            allRowDataList.add(rowData);
        }
        return allRowDataList;
    }

    @Override
    public List<List<Object>> changOIContestRankToExcelRowList(List<OIContestRankVO> oiContestRankVOList, List<String> contestProblemDisplayIDList, String rankShowName) {
        List<List<Object>> allRowDataList = new LinkedList<>();
        for (OIContestRankVO oiContestRankVo : oiContestRankVOList) {
            List<Object> rowData = new LinkedList<>();
            rowData.add(oiContestRankVo.getRank() == -1 ? "*" : oiContestRankVo.getRank().toString());
            rowData.add(oiContestRankVo.getUsername());
            if ("username".equals(rankShowName)) {
                rowData.add(oiContestRankVo.getUsername());
            } else if ("realname".equals(rankShowName)) {
                rowData.add(oiContestRankVo.getRealname());
            } else if ("nickname".equals(rankShowName)) {
                rowData.add(oiContestRankVo.getNickname());
            } else {
                rowData.add("");
            }
            rowData.add(oiContestRankVo.getRealname());
            rowData.add(oiContestRankVo.getSchool());
            rowData.add(oiContestRankVo.getTotalScore());
            HashMap<String, Integer> submissionInfo = oiContestRankVo.getSubmissionInfo();
            for (String displayID : contestProblemDisplayIDList) {
                Integer score = submissionInfo.getOrDefault(displayID, null);
                if (score != null) { // 如果是有提交记录的就写最后一次提交的分数，没有的就写空
                    rowData.add(score);
                } else {
                    rowData.add("");
                }
            }
            allRowDataList.add(rowData);
        }
        return allRowDataList;
    }

    @Override
    public void updateFileToDeleteByGidAndType(Long gid, String type) {
        LambdaUpdateWrapper<File> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(File::getGid, gid).eq(File::getType, type).set(File::getDelete, 1);

        fileMapper.update(null, updateWrapper);
    }
}
